/**
 * 
 */
package wayic.http;

import java.io.IOException;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnection;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethodRetryHandler;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;

/**
 * Creates a default Apache HttpClient. Following features have been customized:
 * -RETRY_HANDLER: new DefaultHttpMethodRetryHandler(5, true)
 * -USER_AGENT: <parameterized>
 * -ALLOW_CIRCULAR_REDIRECTS: true 
 * -REJECT_RELATIVE_REDIRECT: true
 * -MAX_REDIRECTS: 5
 * -ConnectionManagerTimeout: 4000
 * -Multi threaded Connection Manager: new MultiThreadedHttpConnectionManager()
 * -MaxTotalConnections: 4000
 * -ConnectionTimeout: 4000
 * -KEEP-ALIVE connection: false
 * -TcpNoDelay: false
 * 
 * A subclass should override  getUserAgent to return the User-Agent string.
 *  
 * 
 * @author Ashesh Nishant
 *
 */
public abstract class AbstractHttpLoader extends HttpClient implements HttpLoader{
	
	/**
	 * Default constructor. 
	 */
	public AbstractHttpLoader(){
		super();
		super.setHttpConnectionManager(newConnectionManager());
		super.setParams(newClientParams());
	}
	
	/** 
	 * Override this to return the User-Agent string
	 * @see wayic.http.HttpLoader.serv.HttpClientI#getUserAgent()
	 */
	public abstract String getUserAgent();
	
	/* (non-Javadoc)
	 * @see wayic.feed.serv.HttpClientI#execute(org.apache.commons.httpclient.methods.GetMethod)
	 */
	public int execute(GetMethod get) throws IOException, HttpException{
		return super.executeMethod(get);
	}
	
	/**
	 * Shutdown should be called only the HttpCLient is not needed any more. 
	 */
	public void shutdown() {
		HttpConnectionManager manager = super.getHttpConnectionManager();
		manager.closeIdleConnections(0);
		if (manager instanceof MultiThreadedHttpConnectionManager) {
			((MultiThreadedHttpConnectionManager) manager).shutdown();
		}
	}
	
	/**
	 * Override this to create a custom HttpConnectionManager.
	 * @return
	 */
	protected HttpConnectionManager newConnectionManager() {
		HttpConnectionManagerParams params = new HttpConnectionManagerParams();
		params.setMaxTotalConnections(40); // max number of active connections 
		params.setConnectionTimeout(getConnectionTimeout()); //timeout in ms for connection to get established with host.
		params.setSoTimeout(getSocketTimeout()); // socket timeout in ms - timeout for waiting for data
		params.setTcpNoDelay(false); // Nagle's algorithm should not be used.
		
		//Overrides releaseConnection() to disable KEEP-ALIVE connection
		MultiThreadedHttpConnectionManager manager = new MultiThreadedHttpConnectionManager() {
			public void releaseConnection(HttpConnection conn) {
				conn.close();
				super.releaseConnection(conn);
			}
		};
		manager.setParams(params);

		return manager;
	}
	
	/* (non-Javadoc)
	 * @see wayic.feed.serv.HttpClientI#getConnectionTimeout()
	 */
	public int getConnectionTimeout(){
		return 4000;
	}
	
	/* (non-Javadoc)
	 * @see wayic.feed.serv.HttpClientI#getConnectionManagerTimeout()
	 */
	public int getConnectionManagerTimeout(){
		return 4000;
	}
	
	/* (non-Javadoc)
	 * @see wayic.feed.serv.HttpClientI#getSocketTimeout()
	 */
	public int getSocketTimeout(){
		return 4000;
	}

	/* (non-Javadoc)
	 * @see wayic.feed.serv.HttpClientI#getMaxTotalConnections()
	 */
	public int getMaxTotalConnections(){
		return 4000;
	}
	
	/* (non-Javadoc)
	 * @see wayic.feed.serv.HttpClientI#getMaxRedirects()
	 */
	public int getMaxRedirects(){
		return 5;
	}
	
	/* (non-Javadoc)
	 * @see wayic.feed.serv.HttpClientI#getRetryCount()
	 */
	public int getRetryCount(){
		return 5;
	}
	
	/**
	 * Override this to create a custom HttpMethodRetryHandler.
	 * @return
	 */
	protected HttpMethodRetryHandler newRetryHandler() {
		//retries up to 5 times & methods that have successfully sent their request will be retried
		DefaultHttpMethodRetryHandler retryHandler = new DefaultHttpMethodRetryHandler(getRetryCount(), true);

		return retryHandler;
	}
	
	/**
	 * Override this to set custom properties on HttpClientParams.
	 * @return
	 */
	public HttpClientParams newClientParams(){
		HttpClientParams params = new HttpClientParams();
		params.setParameter(HttpMethodParams.RETRY_HANDLER, newRetryHandler());
		params.setParameter(HttpMethodParams.USER_AGENT, getUserAgent());
		params.setParameter(HttpClientParams.ALLOW_CIRCULAR_REDIRECTS, true);
		params.setParameter(HttpClientParams.REJECT_RELATIVE_REDIRECT, false);
		params.setParameter(HttpClientParams.MAX_REDIRECTS, getMaxRedirects());
		params.setConnectionManagerTimeout(getConnectionManagerTimeout()); //timeout for waiting for getting a connection from manager
		return params;
	}
	
}
